package com.dong.mjblog.service;

import com.dong.mjblog.util.FileUtil;
import com.dong.mjblog.util.ImageUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * @Author:dxf
 * @Date:2020/12/6-12-06 20:54
 */
@Service
@Slf4j
public class UploadService extends BaseService {

    @Value("${upload.file.allowType}")
    private String allowFileType;

    @Value("${upload.img.allowType}")
    private String allowImgType;

    @Value("${upload.img.limitSize}")
    private String limitImgSize;

    @Value("${upload.file.limitSize}")
    private String limitFileSize;

    @Value("${upload.file.path}")
    private String filePath;

    @Value("${upload.file.url}")
    private String fileUrl;

    //图片裁切类型
    public static final String CUTTYPE_AUTO = "auto";//自动适应
    public static final String CUTTYPE_CUT = "cut";//切掉多余部分
    public static final String CUTTYPE_FILL = "fill";//填充背景色


    //默认支持的文件上传类型
    private String[] defaultAllowFileType = {"doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf", "zip", "rar", "txt", "mp4"};
    //默认允许上传的文件大小，单位mb
    private int defaultLimitFileSize = 200;

    //默认支持的图片上传类型
    private String[] defaultAllowImgType = {"jpeg", "jpg", "gif", "png", "bmp"};
    //默认允许上传的图片大小，单位mb
    private int defaultLimitImgSize = 2;

    @Data
    public static class UploadFileParam {
        private String[] allowType = {};//允许上传的文件类型
        private int allowFileSize = 0;//文件大小限制，单位mb
    }

    @Data
    public class UploadImgParam extends UploadFileParam {
        //下面参数对上传图片有效，均为可选项
        private String imgCutType = CUTTYPE_AUTO;//图片裁切类型，当图片宽度和高度均大于0时此参数有效
        private int imgWidth = 0;//图片宽度，大于0时有效
        private int imgHeight = 0;//图片高度，大于0时有效
    }

    @Data
    public class UploadResult {
        private int result = 0;//上传结果，1成功，0失败
        private String msg = null;//提示信息，当上传失败时，此字段存放错误提示
        private String urlPath = null;//上传后图片绝对url地址，可用于展示图片或文件的下载链接
        private String savePath = null;//文件上传后的相对路径，用于存储到数据库字段
    }

    @PostConstruct
    public void init() {
        String tmp = this.allowFileType;
        if (tmp != null && !tmp.equals("")) {
            defaultAllowFileType = tmp.split(",");
        }
        tmp = this.allowImgType;
        if (tmp != null && !tmp.equals("")) {
            defaultAllowImgType = tmp.split(",");
        }

        tmp = this.limitFileSize;
        if (tmp != null && !tmp.equals("")) {
            defaultLimitFileSize = Integer.parseInt(tmp);
        }

        tmp = this.limitImgSize;
        if (tmp != null && !tmp.equals("")) {
            defaultLimitImgSize = Integer.parseInt(tmp);
        }

        tmp = this.filePath;
        if (tmp != null && !tmp.equals("")) {
            setFilePath(tmp);
        }

        tmp = this.fileUrl;
        if (tmp != null && !tmp.equals("")) {
            setFileUrl(tmp);
        }
    }

    private File saveFile(MultipartFile file) {
        Date datenow = new Date();
        long thisTime = datenow.getTime();

        String extName = FileUtil.getExtName(file.getOriginalFilename());

        //使用时间戳生成文件名
        String fileName = thisTime + "." + extName;

        //使用日期生成目录
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
        String strDate = formatter.format(datenow);
        String uploadFilePath = getUploadFilePath() + "/" + strDate;

        File targetFile = new File(uploadFilePath, fileName);
        if (!targetFile.getParentFile().exists()) {
            targetFile.getParentFile().mkdirs();
        }

        //保存
        try {
            file.transferTo(targetFile);
        } catch (Exception e) {
            log.error("", e);
        }
        return targetFile;
    }

    public String getSavePathByFile(File file) {
        return "/"+file.getAbsolutePath().replace(getUploadFilePath() + File.separator, "").replace("\\", "/");
    }

    public String getUrlByFile(File file) {
        String savePath = this.getSavePathByFile(file);
        return getUploadUrlPath() + "/" + savePath;
    }


    public UploadResult uploadFile(MultipartFile file) {
        return this.uploadFile(file, null);
    }

    public UploadResult uploadFile(MultipartFile file, UploadFileParam uploadFileParam) {

        UploadResult result = new UploadResult();
        if (file == null) {
            result.setResult(0);
            result.setMsg("参数有误");
            return result;
        }

        if (uploadFileParam == null) {
            uploadFileParam = new UploadFileParam();
        }

        //设置默认参数
        if (uploadFileParam.getAllowType() == null || uploadFileParam.getAllowType().length == 0) {
            uploadFileParam.setAllowType(defaultAllowFileType);
        }
        if (uploadFileParam.getAllowFileSize() == 0) {
            uploadFileParam.setAllowFileSize(defaultLimitFileSize);
        }

        String extName = FileUtil.getExtName(file.getOriginalFilename());
        if (!Arrays.asList(uploadFileParam.getAllowType()).contains(extName)) {
            result.setResult(0);
            result.setMsg("文件类型不符合要求");
            return result;
        }


        if (file.getSize() > uploadFileParam.getAllowFileSize() * 1024 * 1024) {
            result.setResult(0);
            result.setMsg("文件太大，请选择" + uploadFileParam.getAllowFileSize() + "MB以内的文件");
            return result;
        }

        File targetFile = saveFile(file);

        result.setResult(1);
        result.setUrlPath(getUrlByFile(targetFile));
        result.setSavePath(getSavePathByFile(targetFile));
        return result;
    }


    public UploadResult uploadImg(MultipartFile file) {
        return this.uploadImg(file, null);
    }

    public UploadResult uploadImg(MultipartFile file, UploadImgParam uploadImgParam) {
        UploadResult result = new UploadResult();
        if (file == null) {
            result.setResult(0);
            result.setMsg("参数有误");
            return result;
        }

        if (uploadImgParam == null) {
            uploadImgParam = new UploadImgParam();
        }

        //设置默认参数
        if (uploadImgParam.getAllowType() == null || uploadImgParam.getAllowType().length == 0) {
            uploadImgParam.setAllowType(defaultAllowImgType);
        }
        if (uploadImgParam.getAllowFileSize() == 0) {
            uploadImgParam.setAllowFileSize(defaultLimitImgSize);
        }

        String extName = FileUtil.getExtName(file.getOriginalFilename());
        if (!Arrays.asList(uploadImgParam.getAllowType()).contains(extName)) {
            result.setResult(0);
            result.setMsg("文件类型不符合要求");
            return result;
        }

        if (file.getSize() > uploadImgParam.getAllowFileSize() * 1024 * 1024) {
            result.setResult(0);
            result.setMsg("文件太大，请选择" + uploadImgParam.getAllowFileSize() + "MB以内的文件");
            return result;
        }

        File targetFile = saveFile(file);

        //保存
        try {

            //判断是否需要生成缩略图
            if (uploadImgParam.getImgWidth() > 0 && uploadImgParam.getImgHeight() > 0) {
                File newImg = ImageUtil.thumbnailImage(targetFile, uploadImgParam.getImgWidth(), uploadImgParam.getImgHeight(), "s_", uploadImgParam.getImgCutType());
                targetFile.delete();
                targetFile = newImg;
            } else {
                //即便不生成缩略图也要旋转图片，因为很多浏览器不支持image-orientation: from-image属性，无法自动旋转照片
                ImageUtil.rotate(targetFile);
            }

        } catch (Exception e) {
            log.error("", e);
        }

        result.setResult(1);
        result.setUrlPath(getUrlByFile(targetFile));
        result.setSavePath(getSavePathByFile(targetFile));

        return result;
    }
}
